#include <AST/expr/operator/DotAST.hpp>
#include <global.hpp>

DotAST::DotAST(Expr *lhs, Expr *rhs)
    : Var(dynamic_cast<Var *>(rhs)->getName()),
      lhs(dynamic_cast<Var *>(lhs)),
      rhs(dynamic_cast<Var *>(rhs)) {
    assert(this->lhs != nullptr);
    assert(this->rhs != nullptr);
}

llvm::Value *DotAST::codegen() {
    return valCodegen();
}

llvm::Value *DotAST::refCodegen() {
    Value *lAddr = lhs->refCodegen();
    print_v(lAddr);
    const std::string structName =
        lAddr->getType()->getPointerElementType()->getStructName().str();
    if (!theScope.hasStruct(structName)) {
        return logError(
            "DotAST::codegen: struct name " + structName + " not found");
    }
    const StructDef &structDef = theScope.findStruct(structName);
    if (auto i = structDef.findIndex(rhs->getName()); i.has_value()) {
        return builder.CreateStructGEP(
            lAddr, i.value(), lhs->getName() + "." + rhs->getName());
    }
    return logError(
        "DotAST::codegen: struct member name " + rhs->getName() + " not found");
}

llvm::Value *DotAST::valCodegen() {
    Value *addr = refCodegen();
    print_v(addr);
    return builder.CreateLoad(
        addr->getType()->getPointerElementType(), addr, name);
}
